package main

import (
	"fmt"
	"runtime"
	"time"
)

func main() {
	m0()

	m1()

	m2()

	m3()

	fmt.Println("main end")
}

func stack() string {
	var stackBuf [1024]byte
	stackBufLen := runtime.Stack(stackBuf[:], false)
	return string(stackBuf[:stackBufLen])
}

func m0() {
	defer func() {
		fmt.Println("=====m0 recover=====")
		err := recover()
		if err != nil {
			fmt.Println("err:", err)
			fmt.Println(stack())
		}
	}()

	m0_auto()
}

func m0_auto() {
	var arr = []int{0, 1, 2}
	fmt.Println(arr[3])
}

func m1() {
	defer func() {
		fmt.Println("=====m1 recover=====")
		err := recover()
		if err != nil {
			fmt.Println("err:", err)
		}
	}()

	m1_panic()
}

func m1_panic() {
	panic("自己触发一个")
}

func m2() {
	//defer func() {
	//	fmt.Println("=====m2 recover=====")
	//	err := recover()
	//	if err != nil {
	//		fmt.Println("err:", err)
	//	}
	//}()

	// 协程内panic，只能协程内recover，其他协程无法干预
	m2_goroutine()

	time.Sleep(time.Millisecond * 200)
}

func m2_goroutine() {
	go func() {
		defer func() {
			fmt.Println("=====m2 recover=====")
			err := recover()
			if err != nil {
				fmt.Println("err:", err)
			}
		}()

		panic("协程内异常")
	}()
}

// 多次panic，一次recover
func m3() {
	fmt.Println("=====m3 start=====")
	defer func() {
		fmt.Println("defer 1")
		fmt.Println(stack())
		fmt.Println("recover()", recover())
	}()

	defer func() {
		fmt.Println("defer 2")
		panic("panic 2")
	}()

	panic("panic 1")
	fmt.Println("=====m3 end=====")
}
